if SERVER then

/* Load player info */
function LoadPlayerInfo( ply )

	/* Variables */
	local steamID		= SQLStr( ply:SteamID() )
	
	/* Debug output */
	DEBUG:Msg( "Loading info for steam ID " .. steamID, "LoadPlayerInfo" )
	
	/* Query */
	local query			= "SELECT * FROM PlayerInfo WHERE SteamID = " .. steamID
	
	/* Execute the query */
	local result		= sql.Query( query )
	
	/* If nothing was found, create player info and select it */
	if not result then
	
		/* Debug output */
		DEBUG:Msg( "Info not found for steam ID " .. steamID, "LoadPlayerInfo" )
	
		/* Create new player info */
		result = InsertPlayerInfo( ply )
		
		/* Could not create player info */
		if IsSQLError( result ) then
			DEBUG:ErrMsg( "An error occurred while trying to create player info for '" .. ply:Nick() .. "': " .. tostring( sql.LastError() ), "LoadPlayerInfo" )
			return result
		end
		
		/* Load created info */
		result = sql.Query( query )
	end
	
	/* Assign result to the player */
	if result[1] then
		ply.FirstJoin	= tonumber( result[1]["FirstJoin"] )
		ply.LastJoin	= tonumber( result[1]["LastJoin"] )
		ply.Money		= tonumber( result[1]["Money"] )
	end
	
	/* Return the result */
	if not result or not result[1] then return false
	else return result[1] end
end

/* Load object type */
function LoadObjectType( objTypeID )
	
	/* Variables */
	local id	= tostring( objTypeID )
	
	/* Check if the row already exists */
	local result			= sql.Query( "SELECT * FROM ObjectType WHERE ID = " .. id )
	
	/* SQL error handling */
	if IsSQLError( result ) or IsSQLEmpty( result ) then
		DEBUG:ErrMsg( "Object type couldn't be loaded for " .. tostring( objTypeID ), "LoadObjectType" )
		return false
	end
	
	/* Create a class instance */
	local value = ObjectType(
		tonumber( result[1]["ID"] ),
		tostring( result[1]["Name"] ),
		tostring( result[1]["ClassName"] ) )
	
	/* Return the result */
	return value
end

/* Load object ref type */
function LoadObjRefType( objRefTypeID )
	
	/* Variables */
	local id	= tostring( objRefTypeID )
	
	/* Check if the row already exists */
	local result			= sql.Query( "SELECT * FROM ObjRefType WHERE ID = " .. id )
	
	/* SQL error handling */
	if IsSQLError( result ) or IsSQLEmpty( result ) then
		DEBUG:ErrMsg( "Object reference type couldn't be loaded for " .. tostring( objRefTypeID ), "LoadObjRefType" )
		return false
	end
	
	/* Create a class instance */
	local value = ObjRefType(
		tonumber( result[1]["ID"] ),
		tostring( result[1]["Name"] ) )
	
	/* Return the result */
	return value
end

/* Load level info */
function LoadLevelInfo( levelNum )
	
	/* Variables */
	local num			= tostring( levelNum )
	
	/* Check if the team row already exists */
	local result			= sql.Query( "SELECT * FROM LevelInfo WHERE Num = " .. num )
	
	/* SQL error handling */
	if IsSQLError( result ) or IsSQLEmpty( result ) then
		DEBUG:ErrMsg( "Level info couldn't be loaded for " .. tostring( levelNum ), "LoadLevelInfo" )
		return false
	end
	
	/* Create a class instance */
	local value = LevelInfo(
		tonumber( result[1]["Num"] ),
		tonumber( result[1]["RequiredXp"] ) )
	
	/* Return the result */
	return value
end

/* Load object info */
function LoadObjectInfo( objID )
	
	/* Variables */
	local id			= tostring( objID )
	
	/* Check if the row already exists */
	local result			= sql.Query( "SELECT * FROM ObjectInfo WHERE ID = " .. id )
	
	/* SQL error handling */
	if IsSQLError( result ) or IsSQLEmpty( result ) then
		DEBUG:ErrMsg( "Object info couldn't be loaded for " .. tostring( objID ), "LoadObjectInfo" )
		return false
	end
	
	/* Load the object type */
	local tp			= LoadObjectType( result[1]["Type"] )
	if not tp then
		DEBUG:ErrMsg( "The object type " .. tostring( result[1]["Type"] ) .. " could not be found", "LoadObjectInfo" )
		return false
	end
	
	/* Load the object reference type */
	local refTp			= LoadObjRefType( result[1]["ReferenceType"] )
	if not refTp then
		DEBUG:ErrMsg( "The object reference type " .. tostring( result[1]["ReferenceType"] ) .. " could not be found", "LoadObjectInfo" )
		return false
	end
	
	/* Create a class instance */
	local value = ObjectInfo(
		tonumber( result[1]["ID"] ),
		tostring( result[1]["Name"] ),
		tonumber( result[1]["Health"] ),
		tonumber( result[1]["Weight"] ),
		tp,
		tostring( result[1]["Reference"] ),
		refTp,
		tonumber( result[1]["Price"] ) )
	
	/* Return the result */
	return value
end

/* Load loadout */
function LoadLoadout( loadoutID )
	
	/* Variables */
	local id			= tostring( loadoutID )
	
	/* Check if the row already exists */
	local result			= sql.Query( "SELECT * FROM Loadout WHERE ID = " .. id )
	
	/* SQL error handling */
	if IsSQLError( result ) or IsSQLEmpty( result ) then
		DEBUG:ErrMsg( "Loadout couldn't be loaded for " .. tostring( loadoutID ), "LoadLoadout" )
		return false
	end
	
	/* Load primary weapon */
	local primary		= nil
	if result[1]["PrimaryWeapon"] and result[1]["PrimaryWeapon"] != "NULL" then
		primary			= LoadObjectInfo( result[1]["PrimaryWeapon"] )
	else
		DEBUG:Msg( "The primary weapon " .. tostring( result[1]["PrimaryWeapon"] ) .. " could not be found", "LoadLoadout" )
	end
	
	/* Load secondary weapon */
	local secondary		= nil
	if result[1]["SecondaryWeapon"] and result[1]["SecondaryWeapon"] != "NULL" then
		secondary		= LoadObjectInfo( result[1]["SecondaryWeapon"] )
	else
		DEBUG:Msg( "The secondary weapon " .. tostring( result[1]["SecondaryWeapon"] ) .. " could not be found", "LoadLoadout" )
	end
	
	/* Load inventory 1 */
	local inv1			= nil
	if result[1]["Inventory1"] and result[1]["Inventory1"] != "NULL" then
		inv1			= LoadObjectInfo( result[1]["Inventory1"] )
	else
		DEBUG:Msg( "The first inventory item " .. tostring( result[1]["Inventory1"] ) .. " could not be found", "LoadLoadout" )
	end
	
	/* Load inventory 2 */
	local inv2			= nil
	if result[1]["Inventory2"] and result[1]["Inventory2"] != "NULL" then
		inv2			= LoadObjectInfo( result[1]["Inventory2"] )
	else
		DEBUG:Msg( "The second inventory item " .. tostring( result[1]["Inventory2"] ) .. " could not be found", "LoadLoadout" )
	end
	
	/* Load backpack 1 */
	local backpack1		= nil
	if result[1]["Backpack1"] and result[1]["Backpack1"] != "NULL" then
		backpack1		= LoadObjectInfo( result[1]["Backpack1"] )
	else
		DEBUG:Msg( "The first backpack object " .. tostring( result[1]["Backpack1"] ) .. " could not be found", "LoadLoadout" )
	end
	
	/* Load backpack 2 */
	local backpack2		= nil
	if result[1]["Backpack2"] and result[1]["Backpack2"] != "NULL" then
		backpack2		= LoadObjectInfo( result[1]["Backpack2"] )
	else
		DEBUG:Msg( "The second backpack object " .. tostring( result[1]["Backpack2"] ) .. " could not be found", "LoadLoadout" )
	end
	
	/* Create a class instance */
	local value = Loadout(
		tonumber( result[1]["ID"] ),
		tostring( result[1]["Name"] ),
		primary,
		secondary,
		inv1,
		inv2,
		backpack1,
		backpack2 )
	
	/* Return the result */
	return value
end

/* Load team info */
function LoadTeamInfo( teamObj )

	/* Ensure team is valid */
	local tm			= team.GetInfo( teamObj )
	if not tm then
		DEBUG:ErrMsg( "Team not found: " .. tostring( teamObj ), "LoadTeamInfo" )
		return false
	end
	
	/* Format ID */
	teamID				= tostring( tm.ID )
	
	/* Debug output */
	DEBUG:Msg( "Loading info for team '" .. teamObj .. "'", "LoadTeamInfo" )
	
	/* Query */
	local query			= "SELECT * FROM TeamInfo WHERE ID = " .. teamID
	
	/* Execute the query */
	local result		= sql.Query( query )
	
	/* If nothing was found, create team info and select it */
	if not result then
	
		/* Debug output */
		DEBUG:Msg( "Info not found for team " .. teamObj, "LoadTeamInfo" )
	
		/* Create new team info */
		result = InsertTeamInfo( teamObj )
		
		/* Could not create player info */
		if IsSQLError( result ) then
			DEBUG:ErrMsg( "An error occurred while trying to create team info for team '" .. teamObj .. "': " .. tostring( sql.LastError() ), "LoadTeamInfo" )
			return result
		end
		
		/* Load created info */
		result = sql.Query( query )
	end
	
	/* Assign result to the team */
	if result[1] then
	
		/* Debug output */
		DEBUG:Msg( "Name: " .. tostring( result[1]["Name"] ), "LoadTeamInfo" )
		DEBUG:Msg( "Color: " .. color.ToString( color.FromString( result[1]["Color"] ) ), "LoadTeamInfo" )
		DEBUG:Msg( "Max percent: " .. tostring( result[1]["MaxPercent"] ), "LoadTeamInfo" )
		DEBUG:Msg( "Chat name: " .. tostring( result[1]["ChatName"] ), "LoadTeamInfo" )
		DEBUG:Msg( "Default loadout: " .. tostring( result[1]["DefaultLoadout"] ), "LoadTeamInfo" )
		DEBUG:Msg( "Create time: " .. TimeToDateTimeString( tonumber( result[1]["CreateTime"] ) ), "LoadTeamInfo" )
		
		/* Update team info */
		tm.Name				= tostring( result[1]["Name"] )
		tm.Color			= color.FromString( result[1]["Color"] )
		tm.MaxPercent		= tonumber( result[1]["MaxPercent"] )
		tm.ChatName			= tostring( result[1]["ChatName"] )
		tm.DefaultLoadout	= LoadLoadout( tonumber( result[1]["DefaultLoadout"] ) )
		tm.CreateTime		= tonumber( result[1]["CreateTime"] )
		
		/* Debug output */
		DEBUG:Msg( "Team " .. teamObj .. " correctly loaded", "LoadTeamInfo" )
	end
	
	/* Return the result */
	if not result or not result[1] then return false
	else return result[1] end
end

/* Load all teams info */
function LoadTeamsInfo()

	/* Variables */
	local tm = nil

	/* Create mod teams for those that do not exist yet */
	if not team.Valid( "Attackers" ) then
		team.SetUp( 1,	"Attackers",		Color( 40, 232, 19 )	)
		tm					= team.GetInfo( 1 )
		tm.ID				= 1
		tm.MaxPercent		= 40
		tm.ChatName			= "attacker"
		tm.DefaultLoadout	= LoadLoadout( 1 )
		tm.CreateTime		= tostring( os.time() )
	end
	if not team.Valid( "Defenders" ) then
		team.SetUp( 2,	"Defenders",		Color( 232, 19, 29 )	)
		tm					= team.GetInfo( 2 )
		tm.ID				= 2
		tm.MaxPercent		= 20
		tm.ChatName			= "defender"
		tm.DefaultLoadout	= LoadLoadout( 2 )
		tm.CreateTime		= tostring( os.time() )
	end
	if not team.Valid( "Prisoners" ) then
		team.SetUp( 3,	"Prisoners",		Color( 232, 193, 19 )	)
		tm					= team.GetInfo( 3 )
		tm.ID				= 3
		tm.MaxPercent		= 40
		tm.ChatName			= "prisoner"
		tm.DefaultLoadout	= LoadLoadout( 3 )
		tm.CreateTime		= tostring( os.time() )
	end
	
	/* Create spectators team (just in case) */
	if not team.Valid( 1002 ) then
		team.SetUp( 1002,	"Spectators",		Color( 255, 255, 255 )	)
	end
	
	/* Update spectators team */
	tm					= team.GetInfo( 1002 )
	tm.ID				= 1002
	tm.Name				= "Spectators"
	tm.Color			= Color( 255, 255, 255 )
	tm.MaxPercent		= 100
	tm.ChatName			= "spectator"
	tm.DefaultLoadout	= LoadLoadout( 1002 )
	tm.CreateTime		= tostring( os.time() )
	
	/* Load teams info */
	for id,tm in pairs( team.GetGameTeams() ) do
		LoadTeamInfo( tm.ID )
	end
end

/* Load upgrade info */
function LoadUpgradeInfo( upgID )
	
	/* Variables */
	local id			= tostring( upgID )
	
	/* Check if the row already exists */
	local result			= sql.Query( "SELECT * FROM UpgradeInfo WHERE ID = " .. id )
	
	/* SQL error handling */
	if IsSQLError( result ) or IsSQLEmpty( result ) then
		DEBUG:ErrMsg( "Upgrade info couldn't be loaded for " .. tostring( upgID ), "LoadUpgradeInfo" )
		return false
	end
	
	/* Load the level */
	local lvl			= LoadLevelInfo( result[1]["Level"] )
	if not lvl then
		DEBUG:ErrMsg( "The level " .. tostring( result[1]["Level"] ) .. " could not be found", "LoadUpgradeInfo" )
		return false
	end
	
	/* Load the object */
	local obj			= LoadObjectInfo( result[1]["Object"] )
	if not obj then
		DEBUG:ErrMsg( "The level " .. tostring( result[1]["Object"] ) .. " could not be found", "LoadUpgradeInfo" )
		return false
	end
	
	/* Load the previous upgrade */
	local prev			= LoadUpgradeInfo( result[1]["Previous"] )
	if not prev then
		DEBUG:Msg( "The previous upgrade " .. tostring( result[1]["Previous"] ) .. " could not be found", "LoadUpgradeInfo" )
	end
	
	/* Load the next upgrade */
	local nxt			= LoadUpgradeInfo( result[1]["Next"] )
	if not nxt then
		DEBUG:Msg( "The next upgrade " .. tostring( result[1]["Next"] ) .. " could not be found", "LoadUpgradeInfo" )
	end
	
	/* Create a class instance */
	local value = UpgradeInfo(
		tonumber( result[1]["ID"] ),
		tostring( result[1]["Name"] ),
		lvl,
		tonumber( result[1]["AddHealth"] ),
		tonumber( result[1]["AddWeight"] ),
		tonumber( result[1]["Price"] ),
		obj,
		prev,
		nxt )
	
	/* Return the result */
	return value
end

/* Load player stats */
function LoadPlayerStats( SteamID, TeamID )
	
	/* Variables */
	local steamID		= SQLStr( tostring( SteamID ) )
	local teamID		= tostring( TeamID )
	
	/* Check if the row already exists */
	local result			= sql.Query( "SELECT * FROM PlayerStats WHERE SteamID = " .. steamID .. " AND TeamID = " .. teamID )
	
	/* SQL error handling */
	if IsSQLError( result ) or IsSQLEmpty( result ) then
		DEBUG:ErrMsg( "Player stats couldn't be loaded for " .. tostring( SteamID ) .. ", " .. tostring( TeamID ), "LoadPlayerStats" )
		return false
	end
	
	/* Find the player */
	local ply			= player.GetByUniqueID( steamID )
	if not player.IsValid( ply ) then
		DEBUG:ErrMsg( "The player " .. tostring( SteamID ) .. " could not be found", "LoadPlayerStats" )
		return false
	end
	
	/* Find the team */
	local tm			= team.GetInfo( TeamID )
	if not tm then
		DEBUG:ErrMsg( "The team " .. tostring( TeamID ) .. " could not be found", "LoadPlayerStats" )
		return false
	end
	
	/* Load the level */
	local lvl			= LoadLevelInfo( result[1]["Level"] )
	if not lvl then
		DEBUG:ErrMsg( "The level " .. tostring( result[1]["Level"] ) .. " could not be found", "LoadPlayerStats" )
		return false
	end
	
	/* Create a class instance */
	local value = PlayerStats(
		ply,
		tm,
		tonumber( result[1]["Kills"] ),
		tonumber( result[1]["Deaths"] ),
		tonumber( result[1]["Rescued"] ),
		tonumber( result[1]["Escaped"] ),
		tonumber( result[1]["FriendsKilled"] ),
		tonumber( result[1]["EnemiesRescued"] ),
		tonumber( result[1]["Experience"] ),
		tonumber( result[1]["FriendsKilled"] ),
		lvl )
	
	/* Return the result */
	return value
end

/* Load player upgrade */
function LoadPlayerUpgrade( SteamID, UpgID )
	
	/* Variables */
	local steamID		= SQLStr( tostring( SteamID ) )
	local upgrade		= tostring( UpgID )
	
	/* Check if the row already exists */
	local result		= sql.Query( "SELECT * FROM PlayerUpgrade WHERE SteamID = " .. steamID .. " AND Upgrade = " .. upgrade )
	
	/* SQL error handling */
	if IsSQLError( result ) or IsSQLEmpty( result ) then
		DEBUG:ErrMsg( "Player upgrade couldn't be loaded for " .. tostring( SteamID ) .. ", " .. tostring( UpgID ), "LoadPlayerUpgrade" )
		return false
	end
	
	/* Find the player */
	local ply			= player.GetByUniqueID( steamID )
	if not player.IsValid( ply ) then
		DEBUG:ErrMsg( "The player " .. tostring( SteamID ) .. " could not be found", "LoadPlayerUpgrade" )
		return false
	end
	
	/* Load the upgrade */
	local upg			= LoadUpgradeInfo( UpgID )
	if not upg then
		DEBUG:ErrMsg( "The upgrade " .. tostring( UpgID ) .. " could not be found", "LoadPlayerUpgrade" )
		return false
	end
	
	/* Create a class instance */
	local value = PlayerUpgrade(
		ply,
		upg,
		tonumber( result[1]["DateAcquired"] ) )
	
	/* Return the result */
	return value
end

/* Load user info */
function LoadUserInfo( SteamID )

	/* Variables */
	local steamID		= SQLStr( tostring( SteamID ) )
	
	/* Check if the row already exists */
	local result			= sql.Query( "SELECT * FROM UserInfo WHERE SteamID = " .. steamID )
	
	/* SQL error handling */
	if IsSQLError( result ) or IsSQLEmpty( result ) then
		DEBUG:ErrMsg( "User info couldn't be loaded for " .. tostring( SteamID ), "LoadUserInfo" )
		return false
	end
	
	/* Find the player */
	local ply			= player.GetByUniqueID( steamID )
	if not player.IsValid( ply ) then
		DEBUG:ErrMsg( "The player " .. tostring( SteamID ) .. " could not be found", "LoadUserInfo" )
		return false
	end
	
	/* Create a class instance */
	local value = UserInfo(
		ply,
		tostring( result[1]["Login"] ),
		tostring( result[1]["Password"] ),
		tonumber( result[1]["AdminLevel"] ) )
	
	/* Return the result */
	return value
end

end